/*
  * Copyright (c) 2016 MediaTek Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  * General Public License (GPL) Version 2, available from the file
  * COPYING in the main directory of this source tree, or the
  * BSD license below:
  *
  *     Redistribution and use in source and binary forms, with or
  *     without modification, are permitted provided that the following
  *     conditions are met:
  *
  *      - Redistributions of source code must retain the above
  *        copyright notice, this list of conditions and the following
  *        disclaimer.
  *
  *      - Redistributions in binary form must reproduce the above
  *        copyright notice, this list of conditions and the following
  *        disclaimer in the documentation and/or other materials
  *        provided with the distribution.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */

#ifdef SYSTEM_LOG_SUPPORT

#include "rt_config.h"

/* for wireless system event message */
char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = {
	/* system status event */
	"had associated successfully",	/* IW_ASSOC_EVENT_FLAG */
	"had disassociated",	/* IW_DISASSOC_EVENT_FLAG */
	"had deauthenticated",	/* IW_DEAUTH_EVENT_FLAG */
	"had been aged-out and disassociated",	/* IW_AGEOUT_EVENT_FLAG */
	"occurred CounterMeasures attack",	/* IW_COUNTER_MEASURES_EVENT_FLAG */
	"occurred replay counter different in Key Handshaking",	/* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */
	"occurred RSNIE different in Key Handshaking",	/* IW_RSNIE_DIFF_EVENT_FLAG */
	"occurred MIC different in Key Handshaking",	/* IW_MIC_DIFF_EVENT_FLAG */
	"occurred ICV error in RX",	/* IW_ICV_ERROR_EVENT_FLAG */
	"occurred MIC error in RX",	/* IW_MIC_ERROR_EVENT_FLAG */
	"Group Key Handshaking timeout",	/* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */
	"Pairwise Key Handshaking timeout",	/* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */
	"RSN IE sanity check failure",	/* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */
	"set key done in WPA/WPAPSK",	/* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */
	"set key done in WPA2/WPA2PSK",	/* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */
	"connects with our wireless client",	/* IW_STA_LINKUP_EVENT_FLAG */
	"disconnects with our wireless client",	/* IW_STA_LINKDOWN_EVENT_FLAG */
	"scan completed",	/* IW_SCAN_COMPLETED_EVENT_FLAG */
	"scan terminate!! Busy!! Enqueue fail!!",	/* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */
	"channel switch to ",	/* IW_CHANNEL_CHANGE_EVENT_FLAG */
	"wireless mode is not support",	/* IW_STA_MODE_EVENT_FLAG */
	"blacklisted in MAC filter list",	/* IW_MAC_FILTER_LIST_EVENT_FLAG */
	"Authentication rejected because of challenge failure",	/* IW_AUTH_REJECT_CHALLENGE_FAILURE */
	"Scanning",		/* IW_SCANNING_EVENT_FLAG */
	"Start a new IBSS",	/* IW_START_IBSS_FLAG */
	"Join the IBSS",	/* IW_JOIN_IBSS_FLAG */
	"Shared WEP fail",	/* IW_SHARED_WEP_FAIL */
};

#ifdef IDS_SUPPORT
/* for wireless IDS_spoof_attack event message */
char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = {
	"detected conflict SSID",	/* IW_CONFLICT_SSID_EVENT_FLAG */
	"detected spoofed association response",	/* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */
	"detected spoofed reassociation responses",	/* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */
	"detected spoofed probe response",	/* IW_SPOOF_PROBE_RESP_EVENT_FLAG */
	"detected spoofed beacon",	/* IW_SPOOF_BEACON_EVENT_FLAG */
	"detected spoofed disassociation",	/* IW_SPOOF_DISASSOC_EVENT_FLAG */
	"detected spoofed authentication",	/* IW_SPOOF_AUTH_EVENT_FLAG */
	"detected spoofed deauthentication",	/* IW_SPOOF_DEAUTH_EVENT_FLAG */
	"detected spoofed unknown management frame",	/* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */
	"detected replay attack"	/* IW_REPLAY_ATTACK_EVENT_FLAG */
};

/* for wireless IDS_flooding_attack event message */
char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = {
	"detected authentication flooding",	/* IW_FLOOD_AUTH_EVENT_FLAG */
	"detected association request flooding",	/* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */
	"detected reassociation request flooding",	/* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */
	"detected probe request flooding",	/* IW_FLOOD_PROBE_REQ_EVENT_FLAG */
	"detected disassociation flooding",	/* IW_FLOOD_DISASSOC_EVENT_FLAG */
	"detected deauthentication flooding",	/* IW_FLOOD_DEAUTH_EVENT_FLAG */
	"detected 802.1x eap-request flooding"	/* IW_FLOOD_EAP_REQ_EVENT_FLAG */
};
#endif /* IDS_SUPPORT */

#ifdef WSC_INCLUDED
/* for WSC wireless event message */
char const *pWirelessWscEventText[IW_WSC_EVENT_TYPE_NUM] = {
	"PBC Session Overlap",	/* IW_WSC_PBC_SESSION_OVERLAP */
	"This WPS Registrar supports PBC",	/* IW_WSC_REGISTRAR_SUPPORT_PBC */
	"This WPS Registrar supports PIN",	/* IW_WSC_REGISTRAR_SUPPORT_PIN */
	"WPS status success",	/* IW_WSC_STATUS_SUCCESS */
	"WPS status fail",	/* IW_WSC_STATUS_FAIL */
	"WPS 2 mins time out!",	/* IW_WSC_2MINS_TIMEOUT */
	"WPS Send EAPOL_Start!",	/* IW_WSC_SEND_EAPOL_START */
	"WPS Send WscStart!",	/* IW_WSC_SEND_WSC_START */
	"WPS Send M1!",		/* IW_WSC_SEND_M1 */
	"WPS Send M2!",		/* IW_WSC_SEND_M2 */
	"WPS Send M3!",		/* IW_WSC_SEND_M3 */
	"WPS Send M4!",		/* IW_WSC_SEND_M4 */
	"WPS Send M5!",		/* IW_WSC_SEND_M5 */
	"WPS Send M6!",		/* IW_WSC_SEND_M6 */
	"WPS Send M7!",		/* IW_WSC_SEND_M7 */
	"WPS Send M8!",		/* IW_WSC_SEND_M8 */
	"WPS Send WscDone!",	/* IW_WSC_SEND_DONE */
	"WPS Send WscAck!",	/* IW_WSC_SEND_ACK */
	"WPS Send WscNack!",	/* IW_WSC_SEND_NACK */
	"WPS Receive WscStart!",	/* IW_WSC_RECEIVE_WSC_START */
	"WPS Receive M1!",	/* IW_WSC_RECEIVE_M1 */
	"WPS Receive M2!",	/* IW_WSC_RECEIVE_M2 */
	"WPS Receive M3!",	/* IW_WSC_RECEIVE_M3 */
	"WPS Receive M4!",	/* IW_WSC_RECEIVE_M4 */
	"WPS Receive M5!",	/* IW_WSC_RECEIVE_M5 */
	"WPS Receive M6!",	/* IW_WSC_RECEIVE_M6 */
	"WPS Receive M7!",	/* IW_WSC_RECEIVE_M7 */
	"WPS Receive M8!",	/* IW_WSC_RECEIVE_M8 */
	"WPS Receive WscDone!",	/* IW_WSC_RECEIVE_DONE */
	"WPS Receive WscAck!",	/* IW_WSC_RECEIVE_ACK */
	"WPS Receive WscNack!",	/* IW_WSC_RECEIVE_NACK */
	"Not only one candidate found"	/* IW_WSC_MANY_CANDIDATE */
};
#endif /* WSC_INCLUDED */

#ifdef CONFIG_STA_SUPPORT
#ifdef IWSC_SUPPORT
/* for IWSC wireless event messagechar */
const char *pWirelessIWscEventText[IW_IWSC_EVENT_TYPE_NUM] = {
	"IWSC - T1 mins time out!",	/* IW_IWSC_T1_TIMER_TIMEOUT */
	"IWSC - T2 mins time out!",	/* IW_IWSC_T2_TIMER_TIMEOUT */
	"IWSC - Become Registrar",	/* IW_IWSC_BECOME_REGISTRAR */
	"IWSC - Become Enrollee",	/* IW_IWSC_BECOME_ENROLLEE */
	"IWSC - Entry time out",	/* IW_IWSC_ENTRY_TIMER_TIMEOUT */
};
#endif /* IWSC_SUPPORT */
#endif /* CONFIG_STA_SUPPORT */

/*
	========================================================================

	Routine Description:
		Send log message through wireless event

		Support standard iw_event with IWEVCUSTOM. It is used below.

		iwreq_data.data.flags is used to store event_flag that is defined by user.
		iwreq_data.data.length is the length of the event log.

		The format of the event log is composed of the entry's MAC address and
		the desired log message (refer to pWirelessEventText).

			ex: 11:22:33:44:55:66 has associated successfully

		p.s. The requirement of Wireless Extension is v15 or newer.

	========================================================================
*/
VOID RtmpDrvSendWirelessEvent(IN VOID *pAdSrc,
			      IN USHORT Event_flag, IN PUCHAR pAddr, IN UCHAR BssIdx, IN CHAR Rssi)
{
	PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) pAdSrc;
	PSTRING pBuf = NULL, pBufPtr = NULL;
	USHORT event, type, BufLen;
	UCHAR event_table_len = 0;

	if (pAd->CommonCfg.bWirelessEvent == FALSE)
		return;

	type = Event_flag & 0xFF00;
	event = Event_flag & 0x00FF;

	switch (type) {
	case IW_SYS_EVENT_FLAG_START:
		event_table_len = IW_SYS_EVENT_TYPE_NUM;
		break;
#ifdef IDS_SUPPORT
	case IW_SPOOF_EVENT_FLAG_START:
		event_table_len = IW_SPOOF_EVENT_TYPE_NUM;
		break;

	case IW_FLOOD_EVENT_FLAG_START:
		event_table_len = IW_FLOOD_EVENT_TYPE_NUM;
		break;
#endif /* IDS_SUPPORT */
#ifdef WSC_INCLUDED
	case IW_WSC_EVENT_FLAG_START:
		event_table_len = IW_WSC_EVENT_TYPE_NUM;
		break;
#endif /* WSC_INCLUDED */
#ifdef CONFIG_STA_SUPPORT
#ifdef IWSC_SUPPORT
	case IW_IWSC_EVENT_FLAG_START:
		event_table_len = IW_IWSC_EVENT_TYPE_NUM;
		break;
#endif /* IWSC_SUPPORT */
#endif /* CONFIG_STA_SUPPORT */

	default:
		DBGPRINT(RT_DEBUG_ERROR, ("%s - Wrong type = %d\n", __func__, type));
		return;
	}

	if (event_table_len == 0) {
		DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __func__, type));
		return;
	}

	if (event >= event_table_len) {
		DBGPRINT(RT_DEBUG_ERROR,
			 ("%s : The event(%0x02x) is not valid.\n", __func__, event));
		return;
	}

	/*Allocate memory and copy the msg. */
	os_alloc_mem(NULL, (UCHAR **) &pBuf, IW_CUSTOM_MAX_LEN);
	if (pBuf != NULL) {
		/*Prepare the payload */
		memset(pBuf, 0, IW_CUSTOM_MAX_LEN);

		pBufPtr = pBuf;

		if (pAddr)
			pBufPtr +=
			    sprintf(pBufPtr, "(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ",
				    PRINT_MAC(pAddr));
		else if (BssIdx < MAX_MBSSID_NUM(pAd))
			pBufPtr += sprintf(pBufPtr, "(RT2860) BSS(ra%d) ", BssIdx);
		else
			pBufPtr += sprintf(pBufPtr, "(RT2860) ");

		if (type == IW_SYS_EVENT_FLAG_START) {
			pBufPtr += sprintf(pBufPtr, "%s", pWirelessSysEventText[event]);

			if (Event_flag == IW_CHANNEL_CHANGE_EVENT_FLAG)
				pBufPtr += sprintf(pBufPtr, "%3d", Rssi);
		}
#ifdef IDS_SUPPORT
		else if (type == IW_SPOOF_EVENT_FLAG_START)
			pBufPtr +=
			    sprintf(pBufPtr, "%s (RSSI=%d)", pWirelessSpoofEventText[event], Rssi);
		else if (type == IW_FLOOD_EVENT_FLAG_START)
			pBufPtr += sprintf(pBufPtr, "%s", pWirelessFloodEventText[event]);
#endif /* IDS_SUPPORT */
#ifdef WSC_INCLUDED
		else if (type == IW_WSC_EVENT_FLAG_START)
			pBufPtr += sprintf(pBufPtr, "%s", pWirelessWscEventText[event]);
#endif /* WSC_INCLUDED */
#ifdef CONFIG_STA_SUPPORT
#ifdef IWSC_SUPPORT
		else if (type == IW_IWSC_EVENT_FLAG_START)
			pBufPtr += sprintf(pBufPtr, "%s", pWirelessIWscEventText[event]);
#endif /* IWSC_SUPPORT */
#endif /* CONFIG_STA_SUPPORT */

		pBufPtr[pBufPtr - pBuf] = '\0';
		BufLen = pBufPtr - pBuf;

		RtmpOSWrielessEventSend(pAd->net_dev, RT_WLAN_EVENT_CUSTOM, Event_flag, NULL,
					(PUCHAR) pBuf, BufLen);

		os_free_mem(NULL, pBuf);
	} else
		DBGPRINT(RT_DEBUG_ERROR,
			 ("%s : Can't allocate memory for wireless event.\n", __func__));
}

#endif /* SYSTEM_LOG_SUPPORT */
